//
//  HLESessionManager.m
//  HLENetwork_Example
//
//  Created by hle1879 on 2020/9/30.
//  Copyright © 2020 13434436448@163.com. All rights reserved.
//

#import "HLESessionManager.h"
#import <AFNetworking/AFNetworking.h>
#import <AFNetworking/AFNetworkActivityIndicatorManager.h>
#import <objc/runtime.h>
#import "HLEConst.h"
#import "HLENetWorkConfig.h"
#import "HLEBaseRequest.h"
#import "HLEImageUploadRequest.h"
#import "HLEFileUploadRequest.h"
#import "HLEDownloadRequest.h"
#import "HLEBaseResponse.h"
#import "HLEDownLoadResponse.h"
#import "HLENetWorkCache.h"

@interface HLESessionManager ()

@property (nonatomic,strong) AFHTTPSessionManager *sessionManager;

@property (nonatomic,strong) HLENetWorkConfig *config;

@property (nonatomic,assign) BOOL enableLog;

@property (nonatomic,strong,readwrite) NSMutableArray<HLEBaseRequest*> *allRequests;

@end

@implementation HLESessionManager

+ (instancetype)defaultManager{
    HLESessionManager *instance = [[super allocWithZone:NULL]init];
    instance.config = [HLENetWorkConfig defaultConfig];
    return instance;
}

+ (instancetype)initWithConfig:(HLENetWorkConfig*)config{
    HLESessionManager *instance = [[super allocWithZone:NULL]init];
    instance.config = config;
    return instance;
}

- (instancetype)init
{
    self = [super init];
    if (self) {
        self.allRequests = [NSMutableArray new];
    }
    return self;
}

- (void)setConfig:(HLENetWorkConfig *)config{
    _config = config;
    [self configSession];
    [HLENetWorkCache initWithConfig:self.config];
    [self addObserverForConfig];
}

- (void)addObserverForConfig{
    u_int count = 0;
    objc_property_t *properties = class_copyPropertyList([HLENetWorkConfig class], &count);
    for (int i = 0; i < count; i++) {
        const char *propertyName = property_getName(properties[i]);
        NSString *propertyNameString = [NSString stringWithUTF8String:propertyName];
        [self addObserver:self forKeyPath:[NSString stringWithFormat:@"config.%@",propertyNameString] options:NSKeyValueObservingOptionNew context:nil];
    }
    free(properties);
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
    if ([keyPath isEqualToString:@"cachePath"]) {
        [HLENetWorkCache initWithConfig:self.config];
    }else if([keyPath isEqualToString:@"sessionConfiguration"]){
        self.sessionManager = nil;
        [self configSession];
    }else{
        [self configSession];
    }
}

- (void)configSession{
    if (self.config.requestSerializer != HLERequestSerializerDefault) {
        if (self.config.requestSerializer == HLERequestSerializerHTTP) {
            self.sessionManager.requestSerializer = [AFHTTPRequestSerializer serializer];
        }else {
            self.sessionManager.requestSerializer = [AFJSONRequestSerializer serializer];
        }
    }
    if (self.config.responseSerializer != HLEResponseSerializerDefault) {
        if (self.config.responseSerializer == HLEResponseSerializerHTTP) {
            self.sessionManager.responseSerializer = [AFHTTPResponseSerializer serializer];
        }else {
            self.sessionManager.responseSerializer = [AFJSONResponseSerializer serializer];
        }
    }
    
    if (self.config.acceptableContentTypes) {
        [self setAcceptableContentTypes:self.config.acceptableContentTypes];
    }else{
        self.sessionManager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/html", @"text/json", @"text/plain", @"text/javascript", @"text/xml", @"image/*", nil];
    }
    
    if (self.config.timeoutInterval > 0) {
        self.sessionManager.requestSerializer.timeoutInterval = self.config.timeoutInterval;
    }else{
        self.sessionManager.requestSerializer.timeoutInterval = HLE_Request_Timeout;
    }
    
    if (self.config.requestHeader && self.config.requestHeader.count > 0) {
        for (NSString *key in self.config.requestHeader) {
            id value = self.config.requestHeader[key];
            [self.sessionManager.requestSerializer setValue:value forHTTPHeaderField:key];
        }
    }
    
    if (self.config.securityPolicy) {
        self.sessionManager.securityPolicy = self.config.securityPolicy;
    }else{
        self.sessionManager.securityPolicy = [AFSecurityPolicy defaultPolicy];
    }
    
    [[AFNetworkActivityIndicatorManager sharedManager] setEnabled:self.config.activityIndicatorOpen];
    
}

- (void)setAcceptableContentTypes:(NSSet *)acceptableContentTypes{
    if (!acceptableContentTypes || acceptableContentTypes.count == 0) {
        return;
    }
    self.sessionManager.responseSerializer.acceptableContentTypes = acceptableContentTypes;
}

- (void)enableLog:(BOOL)enable{
    _enableLog = enable;
}

- (HLEBaseRequest *)url:(NSString *)URLString method:(HLENetWorkRequestMethod)method parameters:(nullable NSDictionary*)parameters  completion:(nullable void (^)(HLEBaseResponse * _Nonnull response))completion{
    return [self url:URLString method:method parameters:parameters requestHeader:nil cachePolicy:HLECachePolicyRequestWithoutCahce cacheValidTime:CacheValidTimeWeek cacheCompletion:nil responseCompletion:completion];
}

- (HLEBaseRequest *)url:(NSString *)URLString method:(HLENetWorkRequestMethod)method parameters:(nullable NSDictionary*)parameters requestHeader:(nullable NSDictionary*)requestHeader completion:(nullable void (^)(HLEBaseResponse * _Nonnull response))completion{
    return [self url:URLString method:method parameters:parameters requestHeader:requestHeader cachePolicy:HLECachePolicyRequestWithoutCahce cacheValidTime:CacheValidTimeWeek cacheCompletion:nil responseCompletion:completion];
}

- (HLEBaseRequest *)url:(NSString *)URLString method:(HLENetWorkRequestMethod)method parameters:(nullable NSDictionary*)parameters cachePolicy:(HLENetWorkCachePolicy)cachePolicy  cacheValidTime:(NSTimeInterval)validTime cacheCompletion:(nullable void (^)(HLEBaseResponse * _Nonnull response))cacheCompletion responseCompletion:(nullable void (^)(HLEBaseResponse * _Nonnull response))responseCompletion{
    return [self url:URLString method:method parameters:parameters requestHeader:nil cachePolicy:cachePolicy cacheValidTime:validTime cacheCompletion:cacheCompletion responseCompletion:responseCompletion];
}

- (HLEBaseRequest *)url:(NSString *)URLString method:(HLENetWorkRequestMethod)method parameters:(nullable NSDictionary*)parameters  requestHeader:(nullable NSDictionary*)requestHeader cachePolicy:(HLENetWorkCachePolicy)cachePolicy  cacheValidTime:(NSTimeInterval)validTime cacheCompletion:(nullable void (^)(HLEBaseResponse * _Nonnull response))cacheCompletion responseCompletion:(nullable void (^)(HLEBaseResponse * _Nonnull response))responseCompletion{
    HLEBaseRequest *request = [[HLEBaseRequest alloc]init];
    request.url = URLString;
    request.method = method;
    request.params = parameters;
    request.requestHeader = requestHeader;
    request.cachePolicy = cachePolicy;
    request.cacheValidTime = validTime;
    request.session = self;
    request.enableLog = self.enableLog;
    request.cacheCompletion = ^(HLEBaseResponse * _Nonnull response) {
        dispatch_main_async_safe(^{
            cacheCompletion ? cacheCompletion(response) : nil;
        });
    };
    request.responseCompletion = ^(HLEBaseResponse * _Nonnull response) {
        dispatch_main_async_safe(^{
            responseCompletion ? responseCompletion(response) : nil;
        });
    };
    [request sendRequest];
    return request;
}

- (HLEImageUploadRequest *)url:(NSString *)URLString parameters:(nullable NSDictionary*)parameters  requestHeader:(nullable NSDictionary*)requestHeader images:(nonnull NSArray *)images imageScale:(CGFloat)imageScale imageFileName:(nullable NSString*)imageFileName name:(nullable NSString*)name imageType:(nullable NSString*)imageType progress:(nullable void (^)(NSProgress * _Nonnull progress,double progressRate))progress responseCompletion:(nullable void (^)(HLEBaseResponse * _Nonnull response))responseCompletion{
    HLEImageUploadRequest *request = [[HLEImageUploadRequest alloc]init];
    request.url = URLString;
    request.params = parameters;
    request.requestHeader = requestHeader;
    request.images = images;
    request.imageScale = imageScale;
    request.imageFileName = imageFileName;
    request.name = name;
    request.imageType = imageType;
    request.session = self;
    request.enableLog = self.enableLog;
    request.progress = ^(NSProgress * _Nonnull pro, double progressRate) {
        dispatch_main_async_safe(^{
            progress ? progress(pro,progressRate) : nil;
        });
    };
    request.responseCompletion = ^(HLEBaseResponse * _Nonnull response) {
        dispatch_main_async_safe(^{
            responseCompletion ? responseCompletion(response) : nil;
        });
    };
    [request sendRequest];
    return request;
}

- (HLEFileUploadRequest *)url:(NSString *)URLString parameters:(nullable NSDictionary*)parameters  requestHeader:(nullable NSDictionary*)requestHeader filePath:(nonnull NSString *)filePath  name:(nullable NSString*)name progress:(nullable void (^)(NSProgress * _Nonnull progress,double progressRate))progress responseCompletion:(nullable void (^)(HLEBaseResponse * _Nonnull response))responseCompletion{
    HLEFileUploadRequest *request = [[HLEFileUploadRequest alloc]init];
    request.url = URLString;
    request.params = parameters;
    request.requestHeader = requestHeader;
    request.filePath = filePath;
    request.name = name;
    request.session = self;
    request.enableLog = self.enableLog;
    request.progress = ^(NSProgress * _Nonnull pro, double progressRate) {
        dispatch_main_async_safe(^{
            progress ? progress(pro,progressRate) : nil;
        });
    };
    request.responseCompletion = ^(HLEBaseResponse * _Nonnull response)  {
        dispatch_main_async_safe(^{
            responseCompletion ? responseCompletion(response) : nil;
        });
    };
    [request sendRequest];
    return request;
}

- (HLEDownloadRequest *)url:(NSString *)URLString requestHeader:(nullable NSDictionary*)requestHeader folderName:(nonnull NSString *)folderName progress:(nullable void (^)(NSProgress * _Nonnull progress,double progressRate))progress responseCompletion:(nullable void (^)(HLEDownLoadResponse * _Nonnull response))responseCompletion{
    HLEDownloadRequest *request = [[HLEDownloadRequest alloc]init];
    request.url = URLString;
    request.requestHeader = requestHeader;
    request.folderName = folderName;
    request.session = self;
    request.enableLog = self.enableLog;
    request.progress = ^(NSProgress * _Nonnull pro, double progressRate) {
        dispatch_main_async_safe(^{
            progress ? progress(pro,progressRate) : nil;
        });
    };
    request.responseCompletion = ^(HLEBaseResponse * _Nonnull response)  {
        dispatch_main_async_safe(^{
            responseCompletion ?  responseCompletion((HLEDownLoadResponse*)response) : nil;
        });
    };
    [request sendRequest];
    return request;
}

- (HLEDownloadRequest *)resumeData:(nonnull NSData *)resumeData requestHeader:(nullable NSDictionary*)requestHeader folderName:(nonnull NSString *)folderName progress:(nullable void (^)(NSProgress * _Nonnull progress,double progressRate))progress responseCompletion:(nullable void (^)(HLEDownLoadResponse * _Nonnull response))responseCompletion{
    HLEDownloadRequest *request = [[HLEDownloadRequest alloc]init];
    request.requestHeader = requestHeader;
    request.folderName = folderName;
    request.session = self;
    request.enableLog = self.enableLog;
    request.progress = ^(NSProgress * _Nonnull pro, double progressRate) {
        dispatch_main_async_safe(^{
            progress ? progress(pro,progressRate) : nil;
        });
    };
    request.responseCompletion = ^(HLEBaseResponse * _Nonnull response)  {
        dispatch_main_async_safe(^{
            responseCompletion ?  responseCompletion((HLEDownLoadResponse*)response) : nil;
        });
    };
    [request sendRequestWithResumeData:resumeData];
    return request;
}

- (void)cancelAllRequest{
    if ([self.sessionManager.tasks count] > 0) {
        [self.sessionManager.tasks makeObjectsPerformSelector:@selector(cancel)];
        [self.allRequests removeAllObjects];
    }
}

- (void)cancelAllRequestStopSessionWithCancelingTasks:(BOOL)cancelPendingTasks{
    [self.sessionManager invalidateSessionCancelingTasks:cancelPendingTasks];
    [self.allRequests removeAllObjects];
}

- (void)removeCacheWithRequest:(HLEBaseRequest*)request{
    [HLENetWorkCache removeCacheWithRequest:request];
}

- (void)removeCacheWithRequest:(HLEBaseRequest*)request completion:(void(^)(NSString * _Nonnull))completion{
    [HLENetWorkCache removeCacheWithRequest:request completion:completion];
}

- (void)removeAllCache{
    [HLENetWorkCache removeAllCache];
}

- (void)removeAllCacheWithCompletion:(void(^)(void))completion{
    [HLENetWorkCache removeAllCacheWithCompletion:completion];
}

- (NSUInteger)totalCacheSize{
    return [HLENetWorkCache totalCacheSize];
}

- (NSString *)totalCacheSizeDescription{
    return [HLENetWorkCache totalCacheSizeDescription];
}

- (AFHTTPSessionManager*)sessionManager{
    if (!_sessionManager) {
        _sessionManager = [[AFHTTPSessionManager alloc]initWithSessionConfiguration:self.config.sessionConfiguration];
    }
    return _sessionManager;
}

- (void)dealloc{
    NSLog(@"%@=====dealloc",self);
    u_int count = 0;
    objc_property_t *properties = class_copyPropertyList([HLENetWorkConfig class], &count);
    for (int i = 0; i < count; i++) {
        const char *propertyName = property_getName(properties[i]);
        NSString *propertyNameString = [NSString stringWithUTF8String:propertyName];
        [self removeObserver:self forKeyPath:[NSString stringWithFormat:@"config.%@",propertyNameString]];
    }
    free(properties);
}

@end
